﻿using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Yoozoo.Mars.Got;
using Neonagee.LocalPreferences;
using UnityEngine.Rendering.Universal;
using Object = System.Object;
using ShadowResolution = UnityEngine.Rendering.Universal.ShadowResolution;

namespace Yoozoo.Core.Common
{
    public static class QualityHelper
    {
        public static QualityManager QualityMgr => QualityManager.Inst;
        public static PveQualityListener PveQualityListener => QualityMgr.GetMarkQualityListener<PveQualityListener>("PveQualityListener");
        public static ResolutionQualityListener ResolutionQualityListener => QualityMgr.GetMarkQualityListener<ResolutionQualityListener>("ResolutionQualityListener");
        public static UnityQualityListener UnityQualityListener => QualityMgr.GetMarkQualityListener<UnityQualityListener>("UnityQualityListener");
        public static ShaderQualityListener ShaderQualityListener => QualityMgr.GetMarkQualityListener<ShaderQualityListener>("ShaderQualityListener");
        public static CameraQualityListener PveCameraQualityListener => QualityMgr.GetMarkQualityListener<CameraQualityListener>("PveCamera");
        public static CameraQualityListener RpgCameraQualityListener => QualityMgr.GetMarkQualityListener<CameraQualityListener>("RpgCamera");
        public static FpsLimitQualityListener FpsLimitQualityListener => QualityMgr.GetMarkQualityListener<FpsLimitQualityListener>("FpsLimitQualityListener");
        public static GameObjectParentActiveQualityListener GameObjectQualityListener => QualityMgr.GetMarkQualityListener<GameObjectParentActiveQualityListener>("GameObjectParentActiveQualityListener");

        private static ParticleQualityListener _particleQualityListener;
        public static ParticleQualityListener ParticleQualityListener
        {
            get
            {
                if (!_particleQualityListener)
                {
                    if (QualityMgr == null)
                    {
                        return null;
                    }
                    _particleQualityListener =
                        QualityMgr.GetMarkQualityListener<ParticleQualityListener>("ParticleQualityListener");
                }
                return _particleQualityListener;
            }
        }

        public static QualityAdjusterSetting CurrentAdjusterSetting => QualityMgr.currentAdjusterSetting;
        
        public static void InitAdjusterParams(QualityEnum quality)
        {
            // TODO 获取上次游戏自定义的设置（服务器或者本地缓存）
            
            //if (LocalPrefs.HasKey("RenderPrecisionQuality"))
            //    CurrentAdjusterSetting.RenderPrecisionQuality = LocalPrefs.GetInt("RenderPrecisionQuality");
            
            //LocalPrefs.DeleteKey("RenderPrecisionQuality");
            
        }

        public static void SetCurrentAdjusterSetting(QualityEnum quality)
        {
            //...
        }

        public static void ApplyAdjuster(IQualityListener qualityListener)
        {
            if (!QualityMgr.Inited)
            {
                return;
            }
            ApplyResolutionAdjuster(qualityListener);
            ApplyCameraFrustumAdjuster(qualityListener);
            ApplyFpsLimitAdjuster(qualityListener);
            ApplyLightShadowAdjuster(qualityListener);
            ApplyOutputScreenQualityAdjuster(qualityListener);
            ApplyPostEffectAdjuster(qualityListener);
            ApplyPveSceneQualityAdjuster(qualityListener);
            ApplyRenderPrecisionAdjuster(qualityListener);
            ApplyShaderLevelAdjuster(qualityListener);
            ApplyPcSetting(qualityListener);
        }
        
        
        #region CameraFrustumAdjuster

        public static void ApplyCameraFrustumAdjuster(float farDistance, float fov)
        {
            CurrentAdjusterSetting.farClipDistance = farDistance;
            CurrentAdjusterSetting.fov = fov;
            foreach (var qualityListener in QualityMgr.QualityListeners)
            {
                ApplyCameraFrustumAdjuster(qualityListener);
            }
        }

        private static void ApplyCameraFrustumAdjuster(IQualityListener qualityListener)
        {
            if (qualityListener is ICameraFrustumAdjuster cameraFrustumAdjuster)
            {
                cameraFrustumAdjuster.ChangeCameraFrustum(CurrentAdjusterSetting.farClipDistance,CurrentAdjusterSetting.fov);
            }
        }
        #endregion

        #region OutputScreenQualityAdjuster

        public static void ApplyOutputScreenQualityAdjuster(bool hdr, int msaaLevel)
        {
            
#if UNITY_IOS
            CurrentAdjusterSetting.HDR = 1;
#else
            CurrentAdjusterSetting.HDR = hdr ? 1 : 0;
#endif
            
            CurrentAdjusterSetting.MSAALevel = msaaLevel;
            foreach (var qualityListener in QualityMgr.QualityListeners)
            {
                ApplyOutputScreenQualityAdjuster(qualityListener);
            }
        }

        private static void ApplyOutputScreenQualityAdjuster(IQualityListener qualityListener)
        {
            if (qualityListener is IOutputScreenQualityAdjuster screenQualityAdjuster)
            {
                screenQualityAdjuster.ChangeHDRMode(CurrentAdjusterSetting.HDR == 1);
                screenQualityAdjuster.ChangeMSAAMode(CurrentAdjusterSetting.MSAALevel);
            }
        }
        
        #endregion

        #region PostEffectAdjuster

        public static void ApplyPostEffectAdjuster(int style, int level)
        {
            CurrentAdjusterSetting.postEffectStyle = style;
            CurrentAdjusterSetting.postEffectLevel = level;
            foreach (var qualityListener in QualityMgr.QualityListeners)
            {
                ApplyPostEffectAdjuster(qualityListener);
            }
        }

        private static void ApplyPostEffectAdjuster(IQualityListener qualityListener)
        {
            if (qualityListener is IPostEffectAdjuster postEffectAdjuster)
            {
                postEffectAdjuster.ChangePostEffectStyle(CurrentAdjusterSetting.postEffectStyle);
                postEffectAdjuster.ChangePostEffectLevel(CurrentAdjusterSetting.postEffectLevel);
            }
        }

        #endregion

        #region RenderPrecisionAdjuster
        
        public static void ApplyRenderPrecisionAdjuster(int quality)
        {
            CurrentAdjusterSetting.renderPrecisionQuality = quality;
            foreach (var qualityListener in QualityMgr.QualityListeners)
            {
                ApplyRenderPrecisionAdjuster(qualityListener);
            }
        }

        private static void ApplyRenderPrecisionAdjuster(IQualityListener qualityListener)
        {
            if (qualityListener is IRenderPrecisionAdjuster precisionAdjuster)
            {
                precisionAdjuster.ChangeRenderPrecision((QualityEnum)CurrentAdjusterSetting.renderPrecisionQuality);
            }
        }
        
        #endregion

        #region ResolutionAdjuster

        public static void ApplyResolutionAdjuster(float resolutionPercent)
        {
            CurrentAdjusterSetting.resolutionPercent = resolutionPercent;
            foreach (var qualityListener in QualityMgr.QualityListeners)
            {
                ApplyResolutionAdjuster(qualityListener);
            }
        }

        private static void ApplyResolutionAdjuster(IQualityListener qualityListener)
        {
            if (qualityListener is IRenderResolutionAdjuster resolutionAdjuster)
            {
                resolutionAdjuster.ChangeResolution(CurrentAdjusterSetting.resolutionPercent);
            }
        }

        #endregion

        #region ShaderLevelAdjuster

        public static void ApplyShaderLevelAdjuster(int characterLevel,int sceneLevel,int fxLevel)
        {
            CurrentAdjusterSetting.characterGraphicLevel = characterLevel;
            CurrentAdjusterSetting.sceneGraphicLevel = sceneLevel;
            CurrentAdjusterSetting.fxEffectLevel = fxLevel;
            foreach (var qualityListener in QualityMgr.QualityListeners)
            {
                ApplyShaderLevelAdjuster(qualityListener);
            }
        }

        private static void ApplyShaderLevelAdjuster(IQualityListener qualityListener)
        {
            if (qualityListener is IShaderLevelAdjuster shaderLevelAdjuster)
            {
                shaderLevelAdjuster.ChangeCharacterGraphicLevel(CurrentAdjusterSetting.characterGraphicLevel);
                shaderLevelAdjuster.ChangeSceneGraphicLevel(CurrentAdjusterSetting.sceneGraphicLevel);
                shaderLevelAdjuster.ChangeFxEffectLevel(CurrentAdjusterSetting.fxEffectLevel);
            }
        }

        #endregion
        
        #region LightShadowQualityAdjuster

        public static void ApplyLightShadowAdjuster(int lightLevel,int shadowLevel)
        {
            CurrentAdjusterSetting.lightingLevel = lightLevel;
            CurrentAdjusterSetting.shadowLevel = shadowLevel;
            foreach (var qualityListener in QualityMgr.QualityListeners)
            {
                ApplyLightShadowAdjuster(qualityListener);
            }
        }

        public static void ApplyLightShadowAdjuster(IQualityListener qualityListener)
        {
            if (qualityListener is ILightShadowLevelAdjuster lightQualityAdjuster)
            {
                lightQualityAdjuster.ChangeLightLevel((QualityEnum)CurrentAdjusterSetting.lightingLevel);
                lightQualityAdjuster.ChangeShadowLevel((QualityEnum)CurrentAdjusterSetting.shadowLevel);
            }
        }
        #endregion
        
        #region FpsLimitAdjuster

        public static void ApplyFpsLimitAdjuster(int level)
        {
            CurrentAdjusterSetting.fpsLevel = level;
            foreach (var qualityListener in QualityMgr.QualityListeners)
            {
                ApplyFpsLimitAdjuster(qualityListener);
            }
        }

        private static void ApplyFpsLimitAdjuster(IQualityListener qualityListener)
        {
            if (qualityListener is IFpsLimitAdjuster fpsLimitAdjuster)
            {
                fpsLimitAdjuster.ChangeFpsLevel(CurrentAdjusterSetting.fpsLevel);
            }
        }

        public static void ChangeInteractingState(bool isInteracting)
        {
            if (QualityMgr && QualityMgr.QualityListeners!=null)
            {
                foreach (var qualityListener in QualityMgr.QualityListeners)
                {
                    if (qualityListener is IFpsLimitAdjuster fpsLimitAdjuster)
                    {
                        fpsLimitAdjuster.ChangeInteractingState(isInteracting);
                    }
                }
            }

        }
        
        #endregion
        
        #region NpcCountAdjuster

        public static void ApplyPveSceneQualityAdjuster(int npcCount, int carCount)
        {
            CurrentAdjusterSetting.npcCount = npcCount;
            CurrentAdjusterSetting.carCount = carCount;
            foreach (var qualityListener in QualityMgr.QualityListeners)
            {
                ApplyPveSceneQualityAdjuster(qualityListener);
            }
        }

        private static void ApplyPveSceneQualityAdjuster(IQualityListener qualityListener)
        {
            if (qualityListener is IPveSceneQualityAdjuster npcCountAdjuster)
            {
                npcCountAdjuster.ChangeNpcCount(CurrentAdjusterSetting.npcCount,CurrentAdjusterSetting.carCount);
            }
        }

        #endregion

        #region PC设置

        public static AntialiasingMode AntialiasingMode = AntialiasingMode.SubpixelMorphologicalAntiAliasing;
        public static int ShadowDistance = 360;
        public static ShadowResolution ShadowResolution = ShadowResolution._4096;

        public static void LoadPcSetting()
        {
            int antiAliasing = Neonagee.LocalPreferences.LocalPrefs.GetInt("AntiAliasing", 2);
            if (antiAliasing == 2)
            {
                AntialiasingMode = AntialiasingMode.SubpixelMorphologicalAntiAliasing;
            }
            else if (antiAliasing == 1)
            {
                AntialiasingMode = AntialiasingMode.FastApproximateAntialiasing;
            }
            else
            {
                AntialiasingMode = AntialiasingMode.None;
            }
            
            int shadowQuality = Neonagee.LocalPreferences.LocalPrefs.GetInt("ShadowQuality", 2);
            if (shadowQuality == 2)
            {
                ShadowDistance = 400;
                ShadowResolution = ShadowResolution._4096;
            }
            else if (shadowQuality == 1)
            {
                ShadowDistance = 360;
                ShadowResolution = ShadowResolution._2048;
            }
            else
            {
                ShadowDistance = 320;
                ShadowResolution = ShadowResolution._2048;
            }
        }

        // public static void SetPcSetting(AntialiasingMode antialiasingMode, int shadowDistance,
        //     ShadowResolution shadowResolution)
        // {
        //     AntialiasingMode = antialiasingMode;
        //     ShadowDistance = shadowDistance;
        //     ShadowResolution = shadowResolution;
        // }

        public static void ApplyPcSetting(IQualityListener qualityListener)
        {
#if UNITY_STANDALONE_WIN || UNITY_STANDALONE_OSX
            if (qualityListener is IPcCameraAdjuster pcCameraAdjuster)
            {
                pcCameraAdjuster.ChangeAntialiasingMode(AntialiasingMode);
                pcCameraAdjuster.ChangeShadowQuality(ShadowDistance, ShadowResolution);
            }
#endif
        }

        #endregion
        
        public static int GetCacheDeviceGrade()
        {
            return DevicesGrading.Instance.GetCacheDeviceGrade();
        }
        
    }
}